﻿// <author>Netmon Cipher Dev Team</author>
// <date>2009-07-16</date>
// <version>1.0</version>
// <summary>This contains methods to decrypt RC4 encrypted data.</summary>

namespace SSLDecryptionExpert
{
    using System;
    using System.Security.Cryptography;

    /// <summary>
    /// RC4 Key Structure
    /// </summary>
    public struct RC4Key
    {
        /// <summary>
        /// state byte array 
        /// </summary>
        public byte[] State;

        /// <summary>
        /// Derived Key x
        /// </summary>            
        public byte KeyX;

        /// <summary>
        /// Derived Key y
        /// </summary>
        public byte KeyY;

        /// <summary>
        /// Initializes a new instance of the RC4Key struct.
        /// </summary>
        /// <param name="len">Length to initialize</param>
        public RC4Key(int len)
        {
            this.State = new byte[len];
            this.KeyX = 0;
            this.KeyY = 0;
        }
    }

    /// <summary>
    /// The ARC4 Class
    /// </summary>
    public static class ARC4
    {
        /// <summary>
        /// Swaps the bytes
        /// </summary>
        /// <param name="first">First byte</param>
        /// <param name="second">Seconde byte</param>
        public static void SwapByte(ref byte first, ref byte second)
        {
            byte swapByte;
            swapByte = first;
            first = second;
            second = swapByte;
        }

        /// <summary>
        /// prepare RC4 Key from normal key
        /// </summary>
        /// <param name="keyData">intial key data from which RC4 Key is generated</param>
        /// <returns>RC4 Key structure</returns>
        public static RC4Key PrepareKey(byte[] keyData)
        {
            RC4Key key = new RC4Key(256);

            if (keyData != null)
            {                
                byte index1;
                byte index2;
                byte[] state = new byte[key.State.Length];
                short counter;

                for (counter = 0; counter < 256; counter++)
                {
                    state[counter] = (byte)counter;
                }

                key.KeyX = 0;
                key.KeyY = 0;
                index1 = 0;
                index2 = 0;
                for (counter = 0; counter < 256; counter++)
                {
                    index2 = (byte)((keyData[index1] + state[counter] + index2) % 256);
                    SwapByte(ref state[counter], ref state[index2]);
                    index1 = (byte)((index1 + 1) % keyData.Length);
                }

                state.CopyTo(key.State, 0);
                Console.WriteLine("Key Generation Done \n");
            }

            return key;           
        }

        /// <summary>
        /// Performs Encryption or Decryption using the RC4 algorithm
        /// </summary>
        /// <param name="buffer">Data for Decryption</param>
        /// <param name="key">RC4-key for Decryption</param>
        /// <returns>
        /// Encrypted or Decrypted Data depending
        /// on whether encryption or decryption is performed
        /// </returns>
        public static byte[] RC4Crypt(byte[] buffer, RC4Key key)
        {
            if (buffer == null)
            {
                return null;
            }

            byte x;
            byte y;
            byte[] state = new byte[key.State.Length];
            byte xorIndex;
            // Michael: Was short, but caused issue when larger buffer was passed in...
            long counter;

            x = key.KeyX;
            y = key.KeyY;
            char temp;

            key.State.CopyTo(state, 0);
            for (counter = 0; counter < buffer.Length; counter++)
            {
                x = (byte)((x + 1) % 256);
                y = (byte)((state[x] + y) % 256);
                SwapByte(ref state[x], ref state[y]);

                xorIndex = (byte)(state[x] + (state[y] % 256));
                temp = (char)(buffer[counter] ^ state[xorIndex]);
                buffer[counter] = (byte)temp;
            }

            state.CopyTo(key.State, 0);
            key.KeyX = x;
            key.KeyY = y;
            return buffer;
        }
    }
}